package com.wsh.utils.generator;

import cn.hutool.extra.template.*;
import com.wsh.entity.generator.GenBaseConfEntity;
import com.wsh.entity.generator.GenConfEntity;
import com.wsh.entity.generator.GenFileConfEntity;
import com.wsh.utils.FileUtil;
import com.wsh.utils.StringUtils;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.time.LocalDate;
import java.util.*;

public class GenUtils {

    // 获取后台所有模板
    public static List<String> getJavaTemplates() {
        List<String> templateNames = new ArrayList<>();
        templateNames.add("Controller");
        templateNames.add("Dao");
        templateNames.add("Service");
        templateNames.add("ServiceImpl");
        templateNames.add("Entity");
        templateNames.add("Dto");
        templateNames.add("Vo");
        templateNames.add("Mapper");
        return templateNames;
    }

    // 获取前台所有模板
    public static List<String> getViewTemplates() {
        List<String> templateNames = new ArrayList<>();
        templateNames.add("index");
        templateNames.add("Search");
        templateNames.add("Info");
        return templateNames;
    }

    // 获取前台所有模板
    public static List<String> getStaticTemplates() {
        List<String> templateNames = new ArrayList<>();
        templateNames.add("menusql");
        return templateNames;
    }

    // 生成替换模板参数
    private static Map<String, Object> getConfMaps(List<GenConfEntity> genConfEntityList,
                                                   GenBaseConfEntity genBaseConfEntity,
                                                   List<GenFileConfEntity> genFileConfEntityList) {
        Map<String, Object> confMap = new HashMap<>();

        /** 基本配置 */
        String tableName = genBaseConfEntity.getTableName();
        String className = genBaseConfEntity.getClassName();

        // 模块包名
        confMap.put("package", genBaseConfEntity.getPackageName());

        // 实体类名
        confMap.put("className", StringUtils.capitalize(className));

        // 小写开头名
        String changeClassName = StringUtils.uncapitalize(className);
        confMap.put("changeClassName", changeClassName);

        // 用户 时间
        confMap.put("author", genBaseConfEntity.getAuthor());
        confMap.put("date", LocalDate.now().toString());

        // 接口名
        String apiAlias = genBaseConfEntity.getApiName();
        confMap.put("apiAlias", apiAlias);

        /** 表相关 */

        // 表名
        confMap.put("tableName", tableName);

        // 查询主键
        String searchId = genBaseConfEntity.getSearchId();
        confMap.put("searchId", StringUtils.toCamelCase(searchId));
        confMap.put("getId", StringUtils.capitalize(searchId));

        // base config
        confMap.put("isFile", false);
        confMap.put("isDict", false);
        confMap.put("isDate", false);
        confMap.put("isEditor", false);

        // sqlConf
        List<Map<String, Object>> sqlConf = new ArrayList<>();
        Map<String, Object> mainMenu = new HashMap<>();
        // 主菜单
        String mainUuid = UUID.randomUUID().toString();
        mainMenu.put("uuid", mainUuid);
        mainMenu.put("menuName", apiAlias);
        mainMenu.put("type", 1);
        mainMenu.put("parentId", genBaseConfEntity.getMenu());
        mainMenu.put("roleMark", "'" + changeClassName + ":list'");
        mainMenu.put("url", "'"+ changeClassName + "'");
        sqlConf.add(mainMenu);

        String role[] = { ":save", ":del", ":getById" };
        String roleName[] = { "保存", "删除", "查询" };
        // 权限按钮 （增删改查）
        for (int i = 0; i < 3; i++) {
            Map<String, Object> childrenMenu = new HashMap<>();
            childrenMenu.put("uuid", UUID.randomUUID().toString());
            childrenMenu.put("url", "null");
            childrenMenu.put("menuName", apiAlias + roleName[i]);
            childrenMenu.put("type", 2);
            childrenMenu.put("parentId", mainUuid);
            childrenMenu.put("roleMark", "'" + changeClassName + role[i] + "'");
            sqlConf.add(childrenMenu);
        }
        confMap.put("sqlConf", sqlConf);

        List<Map<String, Object>> tables = new ArrayList<>();
        List<Map<String, Object>> searchs = new ArrayList<>();
        List<Map<String, Object>> forms = new ArrayList<>();

        // 保存字段信息
        List<Map<String, Object>> columns = new ArrayList<>();
        for (GenConfEntity genConfEntity : genConfEntityList) {
            Map<String, Object> genConfMap = new HashMap<>();
            String colName = genConfEntity.getColName();

            genConfMap.put("label", genConfEntity.getLabel());
            genConfMap.put("isPk", genConfEntity.getIsPk());
            genConfMap.put("colType", ColUtils.cloToJava(genConfEntity.getColType()));
            genConfMap.put("baseName", colName);

            // 去驼峰
            String colNameToCase = StringUtils.toCamelCase(colName);
            genConfMap.put("colName", StringUtils.toCamelCase(colNameToCase));

            // 首字母大写 get方法使用
            String colNameToCap = StringUtils.capitalize(colNameToCase);
            genConfMap.put("colNameToCap", colNameToCap);

            genConfMap.put("dateRule", null);

            // valid
            genConfMap.put("notBlank", genConfEntity.getNotBlank());
            Integer minLength = genConfEntity.getMinLength();
            Integer maxLength = genConfEntity.getMaxLength();
            genConfMap.put("minLength", minLength);
            genConfMap.put("maxLength", maxLength);
            genConfMap.put("regxpRule", genConfEntity.getRegexpRule());


            // 表单
            if (genConfEntity.getIsForm()) {
                String formType = genConfEntity.getFormType();
                genConfMap.put("formType", StringUtils.isEmpty(formType) ? "input" : formType);

                // 是否导入组件

                if (formType != null) {
                    // 是否开启字典
                    if (formType.equals("radio") || formType.equals("checkbox") || formType.equals("select")) {
                        genConfMap.put("formType", "dict");
                        genConfMap.put("dictValue", genConfEntity.getDictType());
                        genConfMap.put("dictType", formType);
                        confMap.put("isDict", true);
                    }

                    // 是否开启日期
                    if (formType.equals("date")) {
                        String dateRule = genConfEntity.getDateRule();
                        genConfMap.put("dateRule", StringUtils.isNotBlank(dateRule) ? dateRule : "yyyy-MM-dd");
                        confMap.put("isDate", true);
                    }

                    // 是否开启文本编辑器
                    if (formType.equals("editor")) {
                        confMap.put("isEditor", true);
                    }
                }

                forms.add(genConfMap);
            }

            // 表格
            if (genConfEntity.getIsTable()) {
                tables.add(genConfMap);
            }

            // 筛选
            if (genConfEntity.getIsSearch()) {
                String searchType = genConfEntity.getSearchType();
                genConfMap.put("searchType", StringUtils.isEmpty(searchType) ? "eq" : searchType);
                searchs.add(genConfMap);
            }

            columns.add(genConfMap);
        }

        List<Map<String, Object>> files = new ArrayList<>();


        for (GenFileConfEntity genFileConfEntity : genFileConfEntityList) {
            // 开启上传附件
            confMap.put("isFile", true);

            Map<String, Object> fileConfMap = new HashMap<>();
            fileConfMap.put("name", genFileConfEntity.getName());
            fileConfMap.put("filePath", genFileConfEntity.getFilePath());
            fileConfMap.put("processId", genFileConfEntity.getProcessId());
            fileConfMap.put("multiple", genFileConfEntity.getIsMultiple());
            fileConfMap.put("limits", genFileConfEntity.getLimits());
            fileConfMap.put("listType", genFileConfEntity.getListType());

            files.add(fileConfMap);
        }

        // 保存字段列表
        confMap.put("columns", columns);

        // 是否表格
        confMap.put("tables", tables);

        // 是否搜索
        confMap.put("searchs", searchs);

        // 是否表单
        confMap.put("forms", forms);

        // 附件
        confMap.put("files", files);

        return confMap;
    }

    // 代码生成
    public static String genCode(List<GenConfEntity> genConfEntityList, GenBaseConfEntity genBaseConfEntity, List<GenFileConfEntity> genFileConfEntityList) throws Exception {
        String UUID_FILE_PATH = UUID.randomUUID().toString();
        String zipFilePath = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "static/zip").getPath()
                + File.separator + UUID_FILE_PATH + File.separator;
        if (!new File(zipFilePath).exists()) {
            new File(zipFilePath).mkdirs();
        }

        Map<String, Object> confMaps = getConfMaps(genConfEntityList, genBaseConfEntity, genFileConfEntityList);

        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));

        // 后台
        List<String> templatesJava = getJavaTemplates();

        for (String templateName : templatesJava) {
            Template template = engine.getTemplate("java/" + templateName + ".ftl");
            File temmplateFile = new File(zipFilePath + confMaps.get("className").toString() + templateName +
                    (templateName.equals("Mapper") ? ".xml" : ".java"));
            genFile(temmplateFile, template, confMaps);
        }

        // 前台
        List<String> templatesViews = getViewTemplates();
        for (String templateName : templatesViews) {
            Template template = engine.getTemplate("view/" + templateName + ".ftl");
            File temmplateFile = new File(zipFilePath + templateName + ".vue");
            genFile(temmplateFile, template, confMaps);
        }

        // 静态文件
        List<String> staticTemplates = getStaticTemplates();
        for (String templateName : staticTemplates) {
            Template template = engine.getTemplate("static/" + templateName + ".ftl");
            File temmplateFile = new File(zipFilePath + templateName + ".sql");
            genFile(temmplateFile, template, confMaps);
        }
        return UUID_FILE_PATH;
    }

    private static void genFile(File file, Template template, Map<String, Object> confMaps) throws IOException {
        // 生成目标文件
        Writer writer = null;
        try {
            FileUtil.touch(file);
            writer = new FileWriter(file);
            template.render(confMaps, writer);
        } catch (TemplateException | IOException e) {
            throw new RuntimeException(e);
        } finally {
            assert writer != null;
            writer.close();
        }
    }
}
